package com.gitee.faster.webdav.common.helper;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import com.gitee.faster.webdav.common.constant.Constants;
import com.gitee.faster.webdav.exception.ReadException;
import com.gitee.faster.webdav.exception.WebDavException;
import com.gitee.faster.webdav.exception.WriteException;
import com.gitee.faster.webdav.kernel.model.ObjectFactory;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import org.glassfish.jaxb.runtime.marshaller.NamespacePrefixMapper;

import java.io.*;

/**
 * @author hongda.li
 */
public final class XmlHelper {

    private static final NamespacePrefixMapper MAPPER = new CustomPrefixMapper();

    private XmlHelper() {
    }

    private static final JAXBContext JAXB_CONTEXT;

    static {
        try {
            JAXB_CONTEXT = JAXBContext.newInstance(ClassUtil.getPackage(ObjectFactory.class));
        } catch (JAXBException e) {
            throw new WebDavException(e);
        }
    }

    public static String toXml(Object bean) {
        try (StringWriter writer = new StringWriter()) {
            Marshaller marshaller = JAXB_CONTEXT.createMarshaller();
            marshaller.setProperty(Constants.NAME_SPACE_MAPPER, MAPPER);
            marshaller.marshal(bean, writer);
            return writer.toString();
        } catch (Exception e) {
            throw new WriteException("写入XML数据出现异常", e);
        }
    }

    public static <T> T fromXml(String xml, Class<T> clazz) {
        if (CharSequenceUtil.isBlank(xml)) {
            return ReflectUtil.newInstance(clazz);
        }
        try {
            Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
            Object result = unmarshaller.unmarshal(new StringReader(xml));
            return clazz.cast(result);
        } catch (Exception e) {
            throw new ReadException("读取XML数据出现异常", e);
        }
    }

    /**
     * 自定义前缀映射器
     * 部分播放器如 PotPlayer 要求返回的标签必须含有前缀 d
     */
    private static final class CustomPrefixMapper extends NamespacePrefixMapper {

        private CustomPrefixMapper() {
        }

        @Override
        public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
            if (Constants.DAV_PREFIX.equals(namespaceUri)) {
                return Constants.D_PREFIX;
            } else {
                return suggestion;
            }
        }
    }
}
